/*
 * xmlHelper.h
 *
 *  Created on: Nov 14, 2011
 *      Author: fferri
 */

#ifndef XMLHELPER_H_
#define XMLHELPER_H_

#include "resource_system/xmlHelper.h"
#include "resource_system/xmlNodeTree.h"
#include "gtest/gtest.h"
#include "testLogWriter.h"

//////////////////////////////////////////////////////////////////////////////////////////
//
// Pruebas de la clase XmlHelper
//
//////////////////////////////////////////////////////////////////////////////////////////

class XmlHelperTestFixture : public ::testing::Test
{
public:

	const std::string TEST_APP;
	CTestLogWriter* m_tlw;

	void SetUp()
	{
		//std::cout << "Setting up!" << std::endl;
		glog::CGlobalLog& m_log = glog::CGlobalLog::getSingleton();
		m_log.addAppender(TEST_APP);
		boost::shared_ptr<glog::IListener> p(new CTestLogWriter(true));
		m_log.addListener(p, TEST_APP);
		m_log.setMiniumLevel(glog::LOGLEVEL_DEBUG);
	}

	void TearDown()
	{
		//std::cout << "Tearing down!" << std::endl;
		glog::CGlobalLog& m_log = glog::CGlobalLog::getSingleton();
		m_log.processMessages();
		/*
		std::list<std::string> l = m_tlw->getReportedStringList();
		for(std::list<std::string>::iterator it = l.begin(); it != l.end(); ++it)
		{
			std::cout << (*it) << std::endl;
		}
		*/
	}
	XmlHelperTestFixture()
		:TEST_APP("[TEST]")
	{
		glog::CGlobalLog::initSingleton();
		m_tlw = new CTestLogWriter(true);

	}
	virtual ~XmlHelperTestFixture(){
	}
};

//-------------------------------------------------------------------------
// XmlHelper::init(const std::string& APPENDER);
// XmlHelper::openXMLFile();
// Nota: Este segundo metodo es protected y para probarlo hay que hacerlo mediante el metodo init(). En realidad casi todo el trabajo se hace aqui.
//-------------------------------------------------------------------------

// intentamos abrir un fichero que no existe. Lanza una excepcion
TEST_F(XmlHelperTestFixture, opening_non_existent_file_throws_an_exception)
{
	lpe::resman::XMLHelper xhelper("media/files/simple_.xml");
	EXPECT_THROW(xhelper.init(TEST_APP),lpe::core::fileNotFoundException);
}
// intentamos abrir un fichero que no tiene el formato xml correcto. Lanza una excepcion.
TEST_F(XmlHelperTestFixture, opening_wrong_format_file_throws_an_exception)
{
	lpe::resman::XMLHelper xhelper("media/files/simply_wrong.xml");
	EXPECT_THROW(xhelper.init(TEST_APP),lpe::core::xmlParsingException);
}
// leer un fichero correcto.
TEST_F(XmlHelperTestFixture, opening_correct_file_no_throws_exception)
{
	lpe::resman::XMLHelper xhelper("media/files/simple.xml");
	EXPECT_NO_THROW(xhelper.init(TEST_APP));
}
// Si no llamamos a init, el valor de nodetree siempre debe ser NULL
TEST_F(XmlHelperTestFixture, not_calling_init_getRootNode_always_return_NULL)
{
	lpe::resman::XMLHelper xhelper("media/files/simple.xml");
	lpe::resman::XMLNodeTree* nt = xhelper.getXMLRootNode();
	EXPECT_EQ(NULL, nt);
}
//////////////////////////////////////////////////////////////////////////////////////////
//
// Pruebas de la clase XmlNodeTree
//
//////////////////////////////////////////////////////////////////////////////////////////

class XmlNodeTreeTestFixture : public ::testing::Test
{
public:

	const std::string TEST_APP;
	CTestLogWriter* m_tlw;
	lpe::resman::XMLHelper* xhelper;

	// esta clase almacena las opciones para crear el archivo XML de prueba.
	class SampleXmlCreationOptions{
		public:

			bool header;
			std::string m_fileName;
			SampleXmlCreationOptions()
				:header(true)
				,m_fileName("")
			{}
	};

	SampleXmlCreationOptions sco;

	void SetUp()
	{
		//std::cout << "Setting up!" << std::endl;
		glog::CGlobalLog& m_log = glog::CGlobalLog::getSingleton();
		m_log.addAppender(TEST_APP);
		boost::shared_ptr<glog::IListener> p(new CTestLogWriter(true));
		m_log.addListener(p, TEST_APP);
		m_log.setMiniumLevel(glog::LOGLEVEL_DEBUG);
	}
	void TearDown()
	{
		//std::cout << "Tearing down!" << std::endl;
		glog::CGlobalLog& m_log = glog::CGlobalLog::getSingleton();
		m_log.processMessages();
		if(xhelper != NULL)
			delete xhelper;

	}
	bool setupXMLHelper(const std::string& filename)
	{
		xhelper = new lpe::resman::XMLHelper(filename);
		xhelper->init(TEST_APP);
		return true;
	}
	bool createCorrectXMLSampleFile()
	{
		std::ofstream outFile;
		if(sco.m_fileName == "")
			return false;
		outFile.open(sco.m_fileName.c_str(), std::ios::out);

		if(!outFile.is_open())
		{
			std::cout << "Cannot create file\n";
			return false;
		}
		if(sco.header)
			outFile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
			outFile << "<MyLibraryResource>\n";
				outFile << "<MyResource>";
					outFile << "<name>testString</name>\n";
					outFile << "<empty_name></empty_name>\n";
					outFile << "<size>2700</size>\n";
					outFile << "<empty_size></empty_size>\n";
					outFile << "<mean>32.22432</mean>\n";
					outFile << "<deviation>-32</deviation>\n";
					outFile << "<deviation_positive>32</deviation_positive>\n";
					outFile << "<checkResult_a>true</checkResult_a>\n";
					outFile << "<checkResult_b>false</checkResult_b>\n";
					outFile << "<checkResult_c>TruE</checkResult_c>\n";
					outFile << "<MyInnerResource>";
						outFile << "<MyLibraryResource>\n"; // repeated node name
						outFile << "</MyLibraryResource>\n";
					outFile << "</MyInnerResource>";
				outFile << "</MyResource>";
			outFile << "</MyLibraryResource>\n";
		outFile.close();
		return true;
	}
	XmlNodeTreeTestFixture()
		:TEST_APP("[TEST]")
		,xhelper(NULL)
	{
		glog::CGlobalLog::initSingleton();
		m_tlw = new CTestLogWriter(true);
	}
	virtual ~XmlNodeTreeTestFixture(){

	}
};

//-------------------------------------------------------------------------
// XmlNodeTree::readNode()
// a traves de
// XmlHelper::init(const std::string& APPENDER);
// XmlHelper::openXMLFile();
// Nota: Este segundo metodo es protected y para probarlo hay que hacerlo mediante el metodo init(). En realidad casi todo el trabajo se hace aqui.
//-------------------------------------------------------------------------
TEST_F(XmlNodeTreeTestFixture, simple_2_nodes_xml_can_search_a_node_by_name)
{
	sco.m_fileName = "media/files/simple_2_nodes.xml";
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	const lpe::resman::XMLNodeTree* node = xhelper->getXMLRootNode();
	EXPECT_EQ(node->getNodeName(),"menu");
	const lpe::resman::XMLNodeTree* resultNode = node->searchNodeNameRecursive("name");
	EXPECT_EQ(resultNode->getNodeName(), "name");
	EXPECT_EQ(resultNode->getNodeValueAsString(),"Belgian Waffles");
	const lpe::resman::XMLNodeTree* resultNode1 = node->searchNodeNameRecursive("price");
	EXPECT_EQ(resultNode1->getNodeName(), "price");
	EXPECT_NEAR(resultNode1->getNodeValueAsFloat(),5.95,0.00001); // float compare is hell!!
	const lpe::resman::XMLNodeTree* resultNode2 = node->searchNodeNameRecursive("calories");
	EXPECT_EQ(resultNode2->getNodeName(), "calories");
	EXPECT_EQ(resultNode2->getNodeValueAsUnsignedInt(),650);
	const lpe::resman::XMLNodeTree* resultNode3 = node->searchNodeNameRecursive("description");
	EXPECT_EQ(resultNode3->getNodeName(), "description");
	EXPECT_EQ(resultNode3->getNodeValueAsString(),"two of our famous Belgian Waffles with plenty of real maple syrup");

}

TEST_F(XmlNodeTreeTestFixture, readNode_can_deal_with_XML_w_header)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_readNode_can_deal_with_XML_w_header.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
}
TEST_F(XmlNodeTreeTestFixture, readNode_can_deal_with_XML_wo_header)
{
	sco.header = false;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_readNode_can_deal_with_XML_wo_header.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
}
TEST_F(XmlNodeTreeTestFixture, getNodeName_returns_correct_name)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_getNodeName_returns_correct_name.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(nt->getNodeName(),"MyLibraryResource");
}
TEST_F(XmlNodeTreeTestFixture, searchNodeNameRecursive_returns_correct_node)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_searchNodeNameRecursive_returns_correct_node.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(nt->getNodeName(),"MyLibraryResource"); 	 // esto es correcto, pero ademas hay otro nodo mas interior con el mismo nombre.
													 	 // Como la funcion de busqueda siempre empieza por el nodo actual debemos recorrer sus hijos.
	int max = nt->getNumberOfChilds();
	for(int i = 0; i < max; ++i)
	{
		const lpe::resman::XMLNodeTree* nn = nt->getChildNodeAt(i)->searchNodeNameRecursive("MyLibraryResource");
		if(nn != NULL)
		{
			EXPECT_EQ(nn->getNodeName(), "MyLibraryResource");
			break;
		}
		EXPECT_EQ(1,0);  // aqui tiene que fallar si no lo encuentra, puesto que en el fixture esta puesto.
	}
}

// searchNodeNameRecursive retorna NULL cuando no se encuentra el nombre
TEST_F(XmlNodeTreeTestFixture, searchNodeNameRecursive_returns_null_when_not_found)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_searchNodeNameRecursive_returns_correct_node.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(NULL, nt->searchNodeNameRecursive("wont_found_node"));
}

// getNodeValueAsstring devuelve el valor de un nodo como un string
TEST_F(XmlNodeTreeTestFixture, getNodeValueAsString_gets_the_text_node_as_string)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_getNodeValueAsString_gets_the_text_node_as_string.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(nt->searchNodeNameRecursive("name")->getNodeValueAsString(),"testString");
}
// getNodeValueAsstring devuelve el valor de un nodo como un string
TEST_F(XmlNodeTreeTestFixture, getNodeValueAsString_gets_empty_text_when_no_text_is_present)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_getNodeValueAsString_gets_the_text_node_as_string.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(nt->searchNodeNameRecursive("empty_name")->getNodeValueAsString(),"");
}
// getNodeValueAsstring devuelve el valor de un nodo como un unsigned
TEST_F(XmlNodeTreeTestFixture, getNodeValueAsUnsignedInt_gets_the_value_node_as_unsigned_int)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_getNodeValueAsUnsignedInt_gets_the_value_node_as_unsigned_int.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(nt->searchNodeNameRecursive("empty_size")->getNodeValueAsString(),"");
	EXPECT_EQ(nt->searchNodeNameRecursive("empty_size")->getNodeValueAsUnsignedInt(),0);
}
// getNodeValueAsstring devuelve el valor de un nodo como un unsigned
TEST_F(XmlNodeTreeTestFixture, getNodeValueAsUnsignedInt_gets_empty_value_node_as_unsigned_int)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_getNodeValueAsUnsignedInt_gets_the_value_node_as_unsigned_int.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(nt->searchNodeNameRecursive("size")->getNodeValueAsString(),"2700");
	EXPECT_EQ(nt->searchNodeNameRecursive("size")->getNodeValueAsUnsignedInt(),2700);
}
TEST_F(XmlNodeTreeTestFixture, getNodeValueAsUnsignedInt_gets_the_value_node_as_float)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_getNodeValueAsUnsignedInt_gets_the_value_node_as_float.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(nt->searchNodeNameRecursive("mean")->getNodeValueAsString(),"32.22432");
	EXPECT_EQ(nt->searchNodeNameRecursive("mean")->getNodeValueAsUnsignedInt(),32);
	EXPECT_NEAR(nt->searchNodeNameRecursive("mean")->getNodeValueAsFloat(),32.22432,0.00001);
}
TEST_F(XmlNodeTreeTestFixture, getNodeValueAsUnsignedInt_gets_the_value_node_as_negative_int)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_getNodeValueAsUnsignedInt_gets_the_value_node_as_negative_int.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(nt->searchNodeNameRecursive("deviation")->getNodeValueAsString(),"-32");
	EXPECT_EQ(nt->searchNodeNameRecursive("deviation")->getNodeValueAsInt(),-32);
}
TEST_F(XmlNodeTreeTestFixture, getNodeValueAsUnsignedInt_gets_the_value_node_as_int)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_getNodeValueAsUnsignedInt_gets_the_value_node_as_int.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(nt->searchNodeNameRecursive("deviation_positive")->getNodeValueAsString(),"32");
	EXPECT_EQ(nt->searchNodeNameRecursive("deviation_positive")->getNodeValueAsInt(),32);
}
TEST_F(XmlNodeTreeTestFixture, getNodeValueAsUnsignedInt_gets_the_value_node_as_bool)
{
	sco.header = true;
	sco.m_fileName = "media/files/sample_XmlNodeTreeTestFixture_getNodeValueAsUnsignedInt_gets_the_value_node_as_bool.xml";
	EXPECT_TRUE(createCorrectXMLSampleFile());
	EXPECT_NO_THROW(setupXMLHelper(sco.m_fileName));
	lpe::resman::XMLNodeTree* nt = xhelper->getXMLRootNode();
	EXPECT_EQ(nt->searchNodeNameRecursive("checkResult_a")->getNodeValueAsString(),"true");
	EXPECT_EQ(nt->searchNodeNameRecursive("checkResult_a")->getNodeValueAsBool(),true);
	EXPECT_EQ(nt->searchNodeNameRecursive("checkResult_b")->getNodeValueAsString(),"false");
	EXPECT_EQ(nt->searchNodeNameRecursive("checkResult_b")->getNodeValueAsBool(),false);
	EXPECT_EQ(nt->searchNodeNameRecursive("checkResult_c")->getNodeValueAsString(),"TruE");
	EXPECT_EQ(nt->searchNodeNameRecursive("checkResult_c")->getNodeValueAsBool(),true);
}
#endif /* XMLHELPER_H_ */
